﻿namespace ImageProcessing.Forms
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;

    /// <summary>
    /// Form for contrast and brightness modification
    /// </summary>
    public partial class BrightnessAndContrast : Form
    {
        /// <summary>
        /// Variable carrying latest value of brightness.
        /// </summary>
        private int brightnessValue = 0;

        /// <summary>
        /// Boolean to check if just setting values.
        /// </summary>
        private bool doneBrightness = true;

        /// <summary>
        /// Bool to detect which was done first, brightness or contrast.
        /// </summary>
        private bool brightnessFirst = false;

        /// <summary>
        /// Bool to detect if contrast was done before brightness.
        /// </summary>
        private bool contrastFirst = false;
        
        /// <summary>
        /// Carries latest value of contrast.
        /// </summary>
        private int contrastValue = 0;

        /// <summary>
        /// Boolean to check if just setting values.
        /// </summary>
        private bool doneContrast = true;

        /// <summary>
        /// Height of the image in picture box.
        /// </summary>
        private int height = 0;

        /// <summary>
        /// Width of the image opened in the picture box.
        /// </summary>
        private int width = 0;

        /// <summary>
        /// The original image class, to call later when user presses apply.
        /// </summary>
        private DImage originalImage;

        /// <summary>
        /// Old image structure, resized to fit picture box in form.
        /// </summary>
        private ImageStructure[,] oldImage;

        /// <summary>
        /// New image matrix, the one that has operations done on.
        /// </summary>
        private ImageStructure[,] newImage;

        /// <summary>
        /// Initializes a new instance of the <see cref="BrightnessAndContrast"/> class.
        /// </summary>
        /// <param name="originalImg">The original img.</param>
        public BrightnessAndContrast(DImage originalImg)
        {
            this.InitializeComponent();
            this.originalImage = originalImg;
            if (originalImg.Width > this.pcbModifiedImage.Width || originalImg.Height > this.pcbModifiedImage.Height)
            {
                this.oldImage = ResizeImage.BicubicResize(this.pcbOriginalImage.Width, this.pcbOriginalImage.Height, originalImg.ImageStructArray, 3);
                this.height = this.pcbModifiedImage.Height;
                this.width = this.pcbModifiedImage.Width;
            }
            else
            {
                this.oldImage = new ImageStructure[originalImg.Height, originalImg.Width];
                this.oldImage = Operations.CopyImage(originalImg.ImageStructArray, originalImg.Width, originalImg.Height);
                this.height = originalImg.Height;
                this.width = originalImg.Width;
            }

            this.newImage = new ImageStructure[this.height, this.width];
            this.newImage = Operations.CopyImage(this.oldImage, this.width, this.height);
            this.pcbOriginalImage.Image = Operations.DisplayMatrix(this.oldImage);
            this.pcbModifiedImage.Image = Operations.DisplayMatrix(this.newImage);
            this.TxtBrightness.Text = "0";
            this.TxtContrast.Text = "0";
            this.originalImage.BackupImageArray();
        }

        /// <summary>
        /// Handles the Scroll event of the TkbBrightness control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TkbBrightness_Scroll(object sender, EventArgs e)
        {
            if (this.doneBrightness)
            {
                this.doneBrightness = false;
                return;
            }

            this.brightnessValue = int.Parse(this.TkbBrightness.Value.ToString());
            if (!this.contrastFirst)
            {
                this.brightnessFirst = true;
                this.newImage = PixelOperation.BrightnessCorrection(this.oldImage, this.brightnessValue);
                if (this.contrastValue != 0)
                {
                    this.newImage = PixelOperation.ContrastCorrection(this.newImage, this.contrastValue);
                }
            }
            else
            {
                this.newImage = PixelOperation.ContrastCorrection(this.oldImage, this.contrastValue);
                this.newImage = PixelOperation.BrightnessCorrection(this.newImage, this.brightnessValue);
            }

            this.pcbModifiedImage.Image = Operations.DisplayMatrix(this.newImage);
            this.doneBrightness = true;
            this.TxtBrightness.Text = this.TkbBrightness.Value.ToString();
        }

        /// <summary>
        /// Handles the TextChanged event of the txtBrightness control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TxtBrightness_TextChanged(object sender, EventArgs e)
        {
            if (this.doneBrightness)
            {
                this.doneBrightness = false;
                return;
            }

            if (!int.TryParse(this.TxtBrightness.Text, out this.brightnessValue))
            {
                MessageBox.Show("Please enter correct input format, from -255 to 255");
                return;
            }

            if (this.brightnessValue > 255 || this.brightnessValue < 0)
            {
                MessageBox.Show("Please enter correct input format, from -255 to 255");
                return;
            }

            this.brightnessValue = int.Parse(this.TxtBrightness.Text);
            if (!this.contrastFirst)
            {
                this.brightnessFirst = true;
                this.newImage = PixelOperation.BrightnessCorrection(this.oldImage, this.brightnessValue);
                if (this.contrastValue != 0)
                {
                    this.newImage = PixelOperation.ContrastCorrection(this.newImage, this.contrastValue);
                }
            }
            else
            {
                this.newImage = PixelOperation.ContrastCorrection(this.newImage, this.contrastValue);
                this.newImage = PixelOperation.BrightnessCorrection(this.oldImage, this.brightnessValue);
            }

            this.pcbModifiedImage.Image = Operations.DisplayMatrix(this.newImage);
            this.doneBrightness = true;
            this.TxtBrightness.Text = this.TkbBrightness.Value.ToString();
            this.TkbBrightness.Value = this.brightnessValue;
        }

        /// <summary>
        /// Handles the Click event of the button1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BtnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Handles the Click event of the button2 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        /// <summary>
        /// Handles the Click event of the Btn_Rotate control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BtnApply_Click(object sender, EventArgs e)
        {
            if (Main.ImageList[Main.CurrImage].IsVideo)
            {
                DialogResult result = MessageBox.Show("Do you want to process all video?", "", MessageBoxButtons.YesNo);
                if (result == DialogResult.Yes)
                {
                    SaveFileDialog sf = new SaveFileDialog();
                    sf.AddExtension = true;
                    sf.DefaultExt = "avi";
                    sf.Filter = "AVI file (*.avi)|*.avi";
                    sf.ShowDialog();

                    PHVideoCapture.PHInitializeWriter((sf.FileName + '\0').ToArray(), Main.ImageList[Main.CurrImage].Width, Main.ImageList[Main.CurrImage].Height);

                    Main.ImageList[Main.CurrImage].VideoProcessing = true;
                    for (int i = 0; i < Main.ImageList[Main.CurrImage].NumberOfFrames - 1; i++)
                    {
                        BtnApply_Single_Click(sender, e);
                        PHVideoCapture.RecordFrame(Main.ImageList[Main.CurrImage].ImageBitmap);

                        Main.ImageList[Main.CurrImage].ImageBitmap = new Bitmap(Main.ImageList[Main.CurrImage].Width, Main.ImageList[Main.CurrImage].Height, PixelFormat.Format24bppRgb);

                        PHVideoCapture.QueryFrame(Main.ImageList[Main.CurrImage].ImageBitmap);
                    }

                    Main.ImageList[Main.CurrImage].VideoProcessing = false;
                    Main.ImageList[Main.CurrImage].UpdateImage(Main.ImageList[Main.CurrImage].ImageBitmap);
                    PHVideoCapture.ReleaseWriter();
                }
                else
                {
                    BtnApply_Single_Click(sender, e);
                }
            }
            else
            {
                BtnApply_Single_Click(sender, e);
            }
        }

        private void BtnApply_Single_Click(object sender, EventArgs e)
        {
            if (this.brightnessFirst)
            {
                this.originalImage.ImageStructArray = ResizeImage.BicubicResize(this.originalImage.Width, this.originalImage.Height, this.originalImage.ImageStructArray, 3);
                this.originalImage.ImageStructArray = PixelOperation.BrightnessCorrection(this.originalImage.ImageStructArray, this.brightnessValue);
                if (this.contrastValue > 0)
                {
                    this.originalImage.ImageStructArray = PixelOperation.ContrastCorrection(this.originalImage.ImageStructArray, this.contrastValue);
                }

                Main.OperationName = "Brightness: " + this.brightnessValue.ToString() + " and Contrast: " + this.contrastValue.ToString();
                this.originalImage.UpdateImage();
            }
            else if (this.contrastFirst)
            {
                this.originalImage.ImageStructArray = ResizeImage.BicubicResize(this.originalImage.Width, this.originalImage.Height, this.originalImage.ImageStructArray, 3);
                this.originalImage.ImageStructArray = PixelOperation.ContrastCorrection(this.originalImage.ImageStructArray, this.contrastValue);
                if (this.brightnessValue > 0)
                {
                    this.originalImage.ImageStructArray = PixelOperation.BrightnessCorrection(this.originalImage.ImageStructArray, this.brightnessValue);
                }

                Main.OperationName = "Brightness: " + this.brightnessValue.ToString() + " and Contrast: " + this.contrastValue.ToString();
                this.originalImage.UpdateImage();
            }

            this.Close();
        }

        /// <summary>
        /// Handles the Scroll event of the TkbContrast control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TkbContrast_Scroll(object sender, EventArgs e)
        {
            if (this.doneContrast)
            {
                this.doneContrast = false;
                return;
            }

            this.contrastValue = this.TkbContrast.Value;
            if (!this.brightnessFirst)
            {
                this.contrastFirst = true;
                this.newImage = PixelOperation.ContrastCorrection(this.oldImage, this.contrastValue);
                if (this.brightnessValue != 0)
                {
                    this.newImage = PixelOperation.BrightnessCorrection(this.newImage, this.brightnessValue);
                }
            }
            else
            {
                this.newImage = PixelOperation.BrightnessCorrection(this.oldImage, this.brightnessValue);
                this.newImage = PixelOperation.ContrastCorrection(this.newImage, this.contrastValue);
            }

            this.pcbModifiedImage.Image = Operations.DisplayMatrix(this.newImage);
            this.doneContrast = true;
            this.TxtContrast.Text = this.TkbContrast.Value.ToString();
        }

        /// <summary>
        /// Handles the TextChanged event of the TxtContrast control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TxtContrast_TextChanged(object sender, EventArgs e)
        {
            if (this.doneContrast)
            {
                this.doneContrast = false;
                return;
            }

            int contrstValue;
            if (!int.TryParse(this.TxtContrast.Text, out contrstValue))
            {
                MessageBox.Show("Please enter correct input format, from -255 to 255");
                return;
            }

            if (contrstValue > 255 || contrstValue < 0)
            {
                MessageBox.Show("Please enter correct input format, from -255 to 255");
                return;
            }

            this.contrastValue = contrstValue;
            if (!this.brightnessFirst)
            {
                this.contrastFirst = true;
                this.newImage = PixelOperation.ContrastCorrection(this.oldImage, this.contrastValue);
                if (this.brightnessValue != 0)
                {
                    this.newImage = PixelOperation.BrightnessCorrection(this.newImage, this.brightnessValue);
                }
            }
            else
            {
                this.newImage = PixelOperation.BrightnessCorrection(this.oldImage, this.brightnessValue);
                this.newImage = PixelOperation.ContrastCorrection(this.newImage, this.contrastValue);
            }

            this.pcbModifiedImage.Image = Operations.DisplayMatrix(this.newImage);
            this.doneContrast = true;
            this.TkbContrast.Value = contrstValue;
        }
    }
}
